#pragma once

#include <string>
#include <functional>
#include <cstring>
#include <fstream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#include "log.hpp"
#include "../Thread/ThreadPool/ThreadPool.hpp"
#include "Task.hpp"

namespace Server
{
    enum
    {
        USAGE_ERROR = 1,
        SOCKET_ERROR,
        BIND_ERROR,
        LISTEN_ERROR,
        OPEN_ERROR
    };

    using func_t = std::function<void(const std::string&, const uint16_t&)>;

    const uint16_t gport = 8080;
    const int gnacklog = 5;

    class TcpServer
    {
    private:
        struct ThreadDate
        {
            TcpServer *_this;
            int _sockfd;

            ThreadDate(TcpServer* tcpServerThis, int sockfd)
                : _this(tcpServerThis), _sockfd(sockfd)
            {}
        };

    public:
        TcpServer(func_t callback, uint16_t port = gport)
            : _sock_listen(0), _port(port), _callback(callback)
        {}

        void init()
        {
            // 1. 创建socket
            _sock_listen = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock_listen == -1)
            {
                logMessage(FATAL, "create socket error");
                exit(SOCKET_ERROR);
            }
            logMessage(NORMAL, "create soket succes");

            // 2. bind 端口
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;

            if (bind(_sock_listen, (const struct sockaddr*)&local, sizeof(local)) < 0)
            {
                logMessage(FATAL, "socket bind error");
                exit(BIND_ERROR);
            }
            logMessage(NORMAL, "socket bind success");

            // 3. 设置socket 为 listen 状态
            if (listen(_sock_listen, gnacklog) < 0)
            {
                logMessage(FATAL, "socket listen error");
                exit(LISTEN_ERROR);
            }
            logMessage(NORMAL, "socket listen succes");


        }

        void start()
        {
            ThreadPool<Task>::getInstance()->run();
            logMessage(NORMAL, "ThreadPool init succes");
            // signal(SIGCHLD, SIG_IGN);
            while (true)
            {
                // 4. 获取新连接
                struct sockaddr_in client;
                memset(&client, 0, sizeof(client));
                socklen_t clientlen = sizeof(client);
                int sockfd = accept(_sock_listen, (struct sockaddr *)&client, &clientlen);
                if (sockfd < 0)
                {
                    logMessage(ERROR, "socket accept error");
                    continue;
                }
                logMessage(NORMAL, "accept a new link succes, get new sock : %d", sockfd); //
                std::cout << "sock: " << sockfd << std::endl;

                // 多进程版本
                // pid_t id = fork();
                // if (id == 0)
                // {
                //     close(_sock_listen);
                //     // if (fork() > 0)
                //     //     exit(0);
                //     serviceIO(sockfd);
                //     close(sockfd);
                //     exit(0);
                // }
                // close(sockfd);
                
                // 通过信号的方式，让父进程来结束子进程
                // pid_t ret = waitpid(id, nullptr, 0);
                // if (ret > 0)
                // {
                //     std::cout << "wait succes" << ret << std::endl;
                // }

                // 多线程版本
                // pthread_t tid;
                // ThreadDate* td = new ThreadDate(this, sockfd);
                // pthread_create(&tid, nullptr, ThreadRoutine, td);

                // 线程池版本
                ThreadPool<Task>::getInstance()->push(Task(sockfd, serviceIO));
            }
        }

        // static void* ThreadRoutine(void* args)
        // {
        //     pthread_detach(pthread_self());

        //     ThreadDate* td = static_cast<ThreadDate *>(args);
        //     td->_this->serviceIO(td->_sockfd);
        //     close(td->_sockfd);
        //     delete td;
        //     td = nullptr;
        //     return nullptr;
        // }

        

    private:
        int _sock_listen;
        uint16_t _port;

        func_t _callback;
    };
}